package com.zs.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 现在介绍AQS中用来解决线程同步问题的await方法、signal方法和signalAll方法，
 * 这几个方法主要对应的是synchronized中的wait方法、notify方法和notifAll方法。
 *
 * @author madison
 * @description
 * @date 2021/5/26 11:49
 */
public class ReentrantLockTest1 {

    public static void main(String[] args) {
        /** 重入锁*/
        Lock lock = new ReentrantLock();
        /** 生产者锁控制器*/
        Condition producerCondition = lock.newCondition();
        /** 消费者锁控制器*/
        Condition consumerCondition = lock.newCondition();
        Message message = new Message(lock, producerCondition, consumerCondition);
        /** 建几个生产线程*/
        new Thread(new Producer(message)).start();
        new Thread(new Producer(message)).start();
        new Thread(new Producer(message)).start();
        /** 建几个消费线程*/
        new Thread(new Consumer(message)).start();
//        new Thread(new Consumer(message)).start();
//        new Thread(new Consumer(message)).start();
//        new Thread(new Consumer(message)).start();
    }

}


class Message {
    /**
     * 当前消息数量
     */
    private int count = 0;
    /**
     * 信息存放最大限数
     */
    private int maximum = 20;
    /**
     * 重入锁
     */
    private Lock lock;
    /**
     * 生产者锁控制器
     */
    private Condition producerCondition;
    /**
     * 消费者锁控制器
     */
    private Condition consumerCondition;

    public Message() {
    }

    public Message(final Lock lock, final Condition producerCondition, final Condition consumerCondition) {
        this.lock = lock;
        this.producerCondition = producerCondition;
        this.consumerCondition = consumerCondition;
    }

    /**
     * 生产消息
     */
    public void set() {
        /** 获取锁*/
        lock.lock();
        try {
            if (count <= maximum) {
                /** 生产一个消息*/
                System.out.println("生产者 线程" + Thread.currentThread().getName() + "生产了一个消息, 当前有" + (++count) + "个消息");
                /** 唤醒等待的消费者*/
                consumerCondition.signal();
            } else {
                try {
                    /**
                     * 如果当前消息大于 maximum信息最大数
                     * 生产者进入睡眠/等待状态
                     * */
                    producerCondition.await();
                    System.out.println("生产者 线程" + Thread.currentThread().getName() + "进入睡眠");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            /** 释放锁*/
            lock.unlock();
        }
    }

    /**
     * 消费消息
     */
    public void get() {
        /** 获取锁*/
        lock.lock();
        try {
            if (count > 0) {
                /** 消费一个消息*/
                System.out.println("消费者 线程" + Thread.currentThread().getName() + "消费了一个消息, 当前有" + (--count) + "个消息");
                /** 唤醒等待的生产者*/
                producerCondition.signal();
            } else {
                try {
                    /** 如果没有消息, 消费者进入睡眠/等待状态*/
                    consumerCondition.await();
                    System.out.println("消费者 线程" + Thread.currentThread().getName() + "进入睡眠");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            /** 释放锁*/
            lock.unlock();
        }
    }

}

class Producer implements Runnable {
    private Message message;

    public Producer(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            message.set();
        }
    }

}

class Consumer implements Runnable {
    private Message message;

    public Consumer(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            message.get();
        }
    }

}